package com.webex.ta.hydra.gui.table.celleditor;

import com.webex.ta.hydra.Constants;
import com.webex.ta.hydra.core.Command;
import com.webex.ta.hydra.core.KeywordRegistry;
import com.webex.ta.hydra.gui.table.ExpansionToggleBorder;
import com.webex.ta.hydra.gui.table.HydraTable;
import com.webex.ta.hydra.util.HydraUtils;

import javax.swing.*;
import javax.swing.table.TableCellEditor;
import javax.swing.tree.TreeCellEditor;
import java.awt.*;
import java.awt.event.*;
import java.io.Serializable;
import java.util.EventObject;


/**
 * Created by Cisco WebEx.
 * User: vegaz
 * Date: 2010-8-18
 * Time: 12:21:45
 */
//public class KeywordEditor extends DefaultCellEditor {
public class KeywordEditor extends AbstractCellEditor
        implements TableCellEditor, TreeCellEditor {

    protected EditorDelegate delegate;

    protected int clickCountToStart = 2;

    private JComboBox comboBox;

    private HydraTable table;

    public KeywordEditor(HydraTable table) {
        this.table = table;
//        final AutoCompleteComboBox comboBox = new AutoCompleteComboBox(KeywordRegistry.getInstance().getKeywordNamesInCategory());
//        ((AutoCompleteComboBox) editorComponent).setEditable(true);
        comboBox = new JComboBox(KeywordRegistry.getInstance().getKeywordNamesInCategory());
        comboBox.setEditable(true);
        comboBox.setRenderer(new IconCellRenderer());
        comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);

        delegate = new EditorDelegate() {
            public void setValue(Object value) {
                comboBox.setSelectedItem(((Command) value).getKeyword());
            }

            public Object getCellEditorValue() {
                return comboBox.getSelectedItem();
            }

            public boolean shouldSelectCell(EventObject anEvent) {
                if (anEvent instanceof MouseEvent) {
                    MouseEvent e = (MouseEvent) anEvent;
                    return e.getID() != MouseEvent.MOUSE_DRAGGED;
                }
                return true;
            }

            public boolean stopCellEditing() {
                if (comboBox.isEditable()) {
                    // Commit edited value.
                    comboBox.actionPerformed(new ActionEvent(
                            KeywordEditor.this, 0, ""));
                }
                return super.stopCellEditing();
            }
        };
        comboBox.addActionListener(delegate);
    }

    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        Command cmd = (Command)value;
        if (HydraUtils.isController(cmd)) {
            comboBox.setModel(new DefaultComboBoxModel(KeywordRegistry.getInstance().getControllerNames()));
        }
        delegate.setValue(value);
        return comboBox;
    }

    public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) {
        String stringValue = tree.convertValueToText(value, isSelected,
                expanded, leaf, row, false);

        comboBox = new JComboBox(KeywordRegistry.getInstance().getKeywordNamesInCategory());
        comboBox.setEditable(true);
        comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
        comboBox.addActionListener(delegate);

        delegate.setValue(stringValue);
        return comboBox;
    }

    public Object getCellEditorValue() {
        return delegate.getCellEditorValue();

    }

    public boolean isCellEditable(EventObject anEvent) {
        return delegate.isCellEditable(anEvent);
    }

    protected class EditorDelegate implements ActionListener, ItemListener, Serializable {

        /**
         * The value of this cell.
         */
        protected Object value;

        /**
         * Returns the value of this cell.
         *
         * @return the value of this cell
         */
        public Object getCellEditorValue() {
            return value;
        }

        /**
         * Sets the value of this cell.
         *
         * @param value the new value of this cell
         */
        public void setValue(Object value) {
            this.value = value;
        }

        /**
         * Returns true if <code>anEvent</code> is <b>not</b> a
         * <code>MouseEvent</code>.  Otherwise, it returns true
         * if the necessary number of clicks have occurred, and
         * returns false otherwise.
         *
         * @param evt the event
         * @return true  if cell is ready for editing, false otherwise
         * @see #shouldSelectCell
         */
        public boolean isCellEditable(EventObject evt) {
            if (evt instanceof MouseEvent) {
                Point p = ((MouseEvent)evt).getPoint();
                int row = table.rowAtPoint(p);
                int column = table.columnAtPoint(p);
                if (column == Constants.COLUMN_KEYWORD && row != -1) {
                    Command command = table.getModel().getCommandAt(row);
                    if (ExpansionToggleBorder
                            .isExpansionToggle(command.getIndent(), p.x - 20)) {
                        //TODO: replace 20 with the width of breakpoint column
                        return false;
                    }
                }
                return ((MouseEvent) evt).getClickCount() >= clickCountToStart;
            }
            return true;
        }

        /**
         * Returns true to indicate that the editing cell may
         * be selected.
         *
         * @param anEvent the event
         * @return true
         * @see #isCellEditable
         */
        public boolean shouldSelectCell(EventObject anEvent) {
            return true;
        }

        /**
         * Returns true to indicate that editing has begun.
         *
         * @param anEvent the event
         */
        public boolean startCellEditing(EventObject anEvent) {
            return true;
        }

        /**
         * Stops editing and
         * returns true to indicate that editing has stopped.
         * This method calls <code>fireEditingStopped</code>.
         *
         * @return true
         */
        public boolean stopCellEditing() {
            fireEditingStopped();
            return true;
        }

        /**
         * Cancels editing.  This method calls <code>fireEditingCanceled</code>.
         */
        public void cancelCellEditing() {
            fireEditingCanceled();
        }

        /**
         * When an action is performed, editing is ended.
         *
         * @param e the action event
         * @see #stopCellEditing
         */
        public void actionPerformed(ActionEvent e) {
            KeywordEditor.this.stopCellEditing();
        }

        /**
         * When an item's state changes, editing is ended.
         *
         * @param e the action event
         * @see #stopCellEditing
         */
        public void itemStateChanged(ItemEvent e) {
            KeywordEditor.this.stopCellEditing();
        }
    }


    private class IconCellRenderer extends DefaultListCellRenderer {
        @Override
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            String kw = value.toString();
            Icon icon = HydraUtils.getIconForKeyword(kw);
            this.setIcon(icon);
            return this;
        }
    }
}
